package generator;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.fastjson.JSONObject;
import com.asiainfo.ws.PmsGdServicesSrv.DesApprovalIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.DesApprovalResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.FileBean;
import com.asiainfo.ws.PmsGdServicesSrv.FileIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.FileResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdTzxyIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdTzxyResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdfqIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdfqResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdhpjKdjrIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdhpjKdjrResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdhpjZqkhIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdhpjZqkhResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsgIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsgResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZhwgIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZhwgResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZlbjBqIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZlbjBqResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZlbjJrwIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZlbjJrwResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZlbjOltIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZlbjOltResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZqkhIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdsjZqkhResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZhwgIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZhwgResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZlbjBqIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZlbjBqResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZlbjJrwIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZlbjJrwResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZlbjOltIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZlbjOltResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZqkhIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdxqZqkhResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZhwgIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZhwgResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZlbjBqIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZlbjBqResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZlbjJrwIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZlbjJrwResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZlbjOltIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZlbjOltResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZqkhIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.GdysZqkhResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.TzglxmIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.TzglxmResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.WgGroupIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.WgGroupResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.WgPersonIntoBean;
import com.asiainfo.ws.PmsGdServicesSrv.WgPersonResponseBean;
import com.asiainfo.ws.PmsGdServicesSrv.XmysqrInfoBean;
import com.asiainfo.ws.PmsGdServicesSrv.XmysqrResponseBean;

public class AdapterGenerator {

	private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
	private static final String DB_URL = "jdbc:mysql://localhost:3306/test";
	private static final String USER = "root";
	private static final String PASS = "123456";
	private static JSONObject map;
	private static JSONObject map_comment;
	private static PrintWriter pw;
	private static String basePath = "E:/java/j2ee/GZ-projects/yth/zsale/twbpmForYTH/src";
	private static String packageName = "com.asiainfo.ws.PmsGdServicesSrv.adapter.model";
	private static String importPackages = "import com.asiainfo.ws.PmsGdServicesSrv.adapter.model.Remark;";
	private static boolean outConsole = false;

	public static void main(String... args) throws IOException {
		Map<String, Collection<Mapping>> allMapping = getMappings();
		Class<?>[] clzes = new Class<?>[] { /**/
			
			GdxqZlbjOltResponseBean.class,
			GdsjZlbjJrwResponseBean.class,
			GdsjZlbjJrwIntoBean.class,
			GdxqZlbjOltResponseBean.class,
			GdxqZlbjOltIntoBean.class,
			GdsjZlbjOltResponseBean.class,
			GdsjZlbjOltIntoBean.class,
			GdxqZhwgResponseBean.class,
			GdxqZhwgIntoBean.class,
			WgGroupResponseBean.class,
			WgGroupIntoBean.class,
			GdsjZqkhResponseBean.class,
			GdsjZqkhIntoBean.class,
			GdsgResponseBean.class,
			GdsgIntoBean.class,
			GdsjZhwgResponseBean.class,
			GdsjZhwgIntoBean.class,
			DesApprovalResponseBean.class,
			DesApprovalIntoBean.class,
			GdsjZlbjBqResponseBean.class,
			GdsjZlbjBqIntoBean.class,
			GdxqZlbjJrwResponseBean.class,
			GdxqZlbjJrwIntoBean.class,
			GdTzxyResponseBean.class,
			GdTzxyIntoBean.class,
			GdfqResponseBean.class,
			GdfqIntoBean.class,
			WgPersonResponseBean.class,
			WgPersonIntoBean.class,
			GdxqZlbjBqResponseBean.class,
			GdxqZlbjBqIntoBean.class,
			XmysqrResponseBean.class,
			XmysqrInfoBean.class,
			FileResponseBean.class,
			FileIntoBean.class,
			GdysZlbjBqResponseBean.class,
			GdysZlbjBqIntoBean.class,
			TzglxmResponseBean.class,
			TzglxmIntoBean.class,
			GdxqZqkhResponseBean.class,
			GdxqZqkhIntoBean.class,
			GdhpjKdjrResponseBean.class,
			GdhpjKdjrIntoBean.class,
			GdhpjZqkhResponseBean.class,
			GdhpjZqkhIntoBean.class,
			GdysZhwgResponseBean.class,
			GdysZhwgIntoBean.class,
			GdysZlbjOltResponseBean.class,
			GdysZlbjOltIntoBean.class,
			GdysZlbjJrwResponseBean.class,
			GdysZlbjJrwIntoBean.class,
			GdysZqkhResponseBean.class,
			GdsjZhwgIntoBean.class,
			FileBean.class,
			GdysZqkhIntoBean.class,
				
				

				/**/ };

		for (Class<? extends Object> clz : clzes) {
			if (allMapping.containsKey(clz.getSimpleName())) {
				Collection<Mapping> mappings = allMapping.get(clz.getSimpleName());
				toMapcomment(mappings);
				out(clz);
			}else{
				map = new JSONObject();
				map_comment = new JSONObject();
				out(clz);
			}
		}
		System.err.println("完成 ...");
	}

	private static void toMapcomment(Collection<Mapping> mappings) {
		map = new JSONObject();
		map_comment = new JSONObject();
		Iterator<Mapping> it = mappings.iterator();
		while (it.hasNext()) {
			Mapping mapping = it.next();
			map.put(mapping.getOldName(), mapping.getNewName());
			map_comment.put(mapping.getOldName(), mapping.getComment());
		}
	}

	private static Map<String, Collection<Mapping>> getMappings() {
		Connection conn = null;
		Statement stmt = null;
		try {
			Class.forName(JDBC_DRIVER);
			conn = DriverManager.getConnection(DB_URL, USER, PASS);
			System.err.println("连接数据库成功...");
			stmt = conn.createStatement();
			String sql = "SELECT BEAN_NAME, OLD_NAME, NEW_NAME, COMMENT FROM TD_BEAN_MAPPING";
			ResultSet rs = stmt.executeQuery(sql);
			Map<String, Collection<Mapping>> ret = new HashMap<String, Collection<Mapping>>();
			Collection<Mapping> list = null;
			while (rs.next()) {
				String beanName = rs.getString("BEAN_NAME");
				if (!ret.containsKey(beanName)) {
					ret.put(beanName, new ArrayList<Mapping>());
				}
				list = ret.get(beanName);
				Mapping mapping = new Mapping(beanName, rs.getString("OLD_NAME"), rs.getString("NEW_NAME"), rs.getString("COMMENT"));
				list.add(mapping);
			}
			rs.close();
			return ret;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (SQLException se2) {
			}
			try {
				if (conn != null)
					conn.close();
			} catch (SQLException se) {
			}
		}
	}

	private static void out(Class<?> clz) throws IOException {
		String className = clz.getSimpleName();
		String classNameVar = Strings.firstCharToLowerCase(className);
		String adpClassName = className + "Adapter";
		if (outConsole) {
			pw = new PrintWriter(System.out);
		} else {
			File file;
			if (packageName != null && packageName.length() > 0) {
				file = new File(basePath + "/" + packageName.replace(".", "/"));
				// pw = new PrintWriter(new FileWriter(new File(basePath + "/" + packageName.replace(".", "/") + "/" + adpClassName +  ".java")));
			} else {
				file = new File(basePath);
				// pw = new PrintWriter(new FileWriter(new File(basePath + "/" +  adpClassName + ".java")));
			}
			if (!file.exists())
				file.mkdirs();
			pw = new PrintWriter(new FileWriter(new File(file, adpClassName + ".java")));
		}
		if (packageName != null && packageName.length() > 0) {
			outPrintln("package " + packageName + ";\n");
		}

		outPrintln("import " + clz.getName() + ";\n");

		if (importPackages != null && importPackages.length() > 0) {
			outPrintln(importPackages + ";\n");
		}

		outPrintln("public class " + adpClassName + " { \n");
		List<Field> fs = getClassFields(clz);
		List<Field> listFs = new ArrayList<Field>();
		for (Field f : fs) {
			if (f.getType() == List.class) {
				listFs.add(f);
			}
		}
		fs.removeAll(listFs);
		fs.addAll(listFs);
		genFields(fs, className, adpClassName, classNameVar);
		genConstruct(fs, className, adpClassName, classNameVar);
		genConvertMethod(fs, className, adpClassName, classNameVar);
		genGetAndSetMethod(fs, className, adpClassName, classNameVar);
		outPrintln("\n}\n");
		// genEndTempleCode(fs, className, adpClassName, classNameVar);
		pw.flush();
		if (!outConsole) {
			try {
				pw.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private static List<Field> getClassFields(Class<?> clz) {
		List<Field> fsList = new ArrayList<Field>();
		Field[] fs = clz.getDeclaredFields();
		for (Field f : fs) {
			if (f.getDeclaringClass() == clz) {
				fsList.add(f);
			}
		}
		if (clz.getSuperclass() == null)
			return fsList;
		Class<?> superclass = clz.getSuperclass();
		fs = superclass.getDeclaredFields();
		for (Field f : fs) {
			if (f.getDeclaringClass() == superclass) {
				fsList.add(f);
			}
		}
		return fsList;
	}

	private static void genFields(List<Field> fs, String className, String adpClassName, String classNameVar) {
		for (Field f : fs) {
			String name = f.getName();
			String typeName = f.getType().getName().replaceAll("^java\\.lang\\.","");
			boolean isList = false;
			if (f.getType() == List.class) {
				Class<?> listParameterizedType = getListParameterizedType(f);
				typeName = String.format("java.util.List<%s>", listParameterizedType.getSimpleName() + "Adapter");
				isList = true;
			}
			String comment = map_comment.getString(name);
			if (comment == null) {
				comment = "待补充";
			}
			if (map.containsKey(name)) {
				String newName = map.getString(name);
				if (isList)
					newName += "Adapters";
				outPrintln("\t@Remark(oldName = \"" + name + "\", newName = \"" + newName + "\", comment = \"" + comment + "\")\n\tprotected " + typeName + " " + newName + ";");
			} else {
				if (isList)
					name += "Adapters";
				outPrintln("\t@Remark(oldName = \"" + name + "\", newName = \"" + name + "\", comment = \"" + comment + "\")\n\tprotected " + typeName + " " + name + ";");
			}
		}
	}

	private static Class<?> getListParameterizedType(Field f) {
		Type genericType = f.getGenericType();
		if (genericType instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) genericType;
			Class<?> parameterizedtype = (Class<?>) parameterizedType.getActualTypeArguments()[0];
			return parameterizedtype;
		}
		return null;
	}

	private static void genConstruct(List<Field> fs, String className, String adpClassName, String classNameVar) {

		outPrintln(String.format("\n\tpublic %s() {", adpClassName, className, classNameVar));
		outPrintln("\t}");
		outPrintln(String.format("\n\tpublic %s(%s %s) {", adpClassName, className, classNameVar));
		for (Field f : fs) {
			String name = f.getName();
			if (f.getType() == List.class) {
				Class<?> listParameterizedType = getListParameterizedType(f);
				String adpClassNameVar = Strings.firstCharToLowerCase(listParameterizedType.getSimpleName()) + "Adapters";
				outPrintln(String.format(
						"\t\tjava.util.List<%s> beans = %s.get%s();\n" //
								+ "\t\tif (beans == null || beans.isEmpty()) {\n" //
								+ "\t\t  this.%s = java.util.Collections.emptyList();\n" //
								+ "\t\t} else {\n"//
								+ "\t\t  this.%s = new java.util.ArrayList<%s>(beans.size());\n" //
								+ "\t\t  for (%s bean : beans) {\n" //
								+ "\t\t    this.%s.add(new %s(bean));\n" //
								+ "\t\t  }\n" + "\t\t}", //
						listParameterizedType.getName(), //
						classNameVar, //
						listParameterizedType.getSimpleName(), //
						adpClassNameVar, //
						adpClassNameVar, //
						listParameterizedType.getSimpleName() + "Adapter", //
						listParameterizedType.getName(), //
						adpClassNameVar, //
						listParameterizedType.getSimpleName() + "Adapter")); //
				continue;
			}
			if (map.containsKey(name)) {
				outPrintln(String.format("\t\tthis.%s = %s.get%s(); ", map.getString(name), classNameVar, Strings.firstCharToUpperCase(name)));
			} else {
				outPrintln(String.format("\t\tthis.%s = %s.get%s(); ", name, classNameVar, Strings.firstCharToUpperCase(name)));
			}
		}
		outPrintln("\t}\n");
	}

	private static String getMethodByType(Class<?> type) {
		if (type == BigDecimal.class) {
			return "get" + "BigDecimal";
		}
		if (type == String.class) {
			return "get" + "String";
		}
		if (type == Integer.class) {
			return "get" + "Integer";
		}
		return null;
	}

	private static void genConvertMethod(List<Field> fs, String className, String adpClassName, String classNameVar) {
		outPrintln(String.format("\tpublic %s to%s() {\n" + "\t\t%s %s = new %s();", className, className, className, classNameVar, className));
		for (Field f : fs) {
			if (f.getType() == List.class)
				continue;
			String name = f.getName();
			if (map.containsKey(name)) {
				outPrintln(String.format("\t\t%s.set%s(this.%s); ", classNameVar, Strings.firstCharToUpperCase(name), map.getString(name)));
			} else {
				outPrintln(String.format("\t\t%s.set%s(this.%s); ", classNameVar, Strings.firstCharToUpperCase(name), name));
			}
		}
		outPrintln(String.format("\t\treturn %s;", classNameVar));
		outPrintln("\t}\n");
	}

	private static void genGetAndSetMethod(List<Field> fs, String className, String adpClassName, String classNameVar) {
		for (Field f : fs) {
			String name = f.getName();
			String typeName = f.getType().getName().replaceAll("^java\\.lang\\.","");
			String comment = map_comment.getString(name);
			if (comment == null) {
				comment = "待补充";
			}
			if (map.containsKey(name)) {
				String newName = map.getString(name);
				if (f.getType() == List.class) {
					typeName = typeName + "<" + Strings.firstCharToUpperCase(newName) + "Adapter>";
					newName += "Adapters";
				}
				outPrintln("\t/**\n\t * " + comment + "\n\t */");
				outPrintln(String.format("\tpublic %s get%s() {\n" + "\t\treturn %s;\n" + "\t}\n", typeName, Strings.firstCharToUpperCase(newName), newName));
				if (f.getType() == List.class)
					continue;
				outPrintln("\t/**\n\t * " + comment + "\n\t */");
				outPrintln(String.format("\tpublic %s set%s(%s %s) {\n" + "\t\tthis.%s = %s;\n" + "\t\treturn this;" + "\n\t}\n", adpClassName, Strings.firstCharToUpperCase(newName), typeName, newName, newName, newName, newName));
			} else {
				if (f.getType() == List.class) {
					typeName = typeName + "<" + Strings.firstCharToUpperCase(name) + "Adapter>";
					name += "Adapters";
				}
				outPrintln("\t/**\n\t * " + comment + "\n\t */");
				outPrintln(String.format("\tpublic %s get%s() {\n" + "\t\treturn %s;\n" + "\t}\n", typeName, Strings.firstCharToUpperCase(name), name));
				if (f.getType() == List.class)
					continue;
				outPrintln("\t/**\n\t * " + comment + "\n\t */");
				outPrintln(String.format("\tpublic %s set%s(%s %s) {\n" + "\t\tthis.%s = %s;\n" + "\t\treturn this;" + "\n\t}\n", adpClassName, Strings.firstCharToUpperCase(name), typeName, name, name, name, name));
			}
		}
	}

	private static void genEndTempleCode(List<Field> fs, String className, String adpClassName, String classNameVar) {
		String adpClassVar = Strings.firstCharToLowerCase(adpClassName);
		outPrintln(String.format("\n\n/***************************************************************************\n\n"));
		for (Field f : fs) {
			String name = f.getName();
			String methodName = getMethodByType(f.getType());
			if (methodName == null)
				continue;
			if (map.containsKey(name)) {
				String newName = map.getString(name);
				outPrintln(String.format("\t\tif (params.get(\"%s\") != null)", newName));
				outPrintln(String.format("\t\t\t%s.set%s(params.%s(\"%s\"));", adpClassVar, Strings.firstCharToUpperCase(newName), methodName, newName));
			} else {
				outPrintln(String.format("\t\tif (params.get(\"%s\") != null)", name));
				outPrintln(String.format("\t\t\t%s.set%s(params.%s(\"%s\"));", adpClassVar, Strings.firstCharToUpperCase(name), methodName, name));
			}
		}
		outPrintln(String.format("\n\n***************************************************************************/ "));
	}

	private static void outPrintln(String x) {
		pw.println(x);
	}

}

class Strings {

	/**
	 * 首字母变小写
	 */
	public static String firstCharToLowerCase(String str) {
		char firstChar = str.charAt(0);
		if (firstChar >= 'A' && firstChar <= 'Z') {
			char[] arr = str.toCharArray();
			arr[0] += ('a' - 'A');
			return new String(arr);
		}
		return str;
	}

	/**
	 * 首字母变大写
	 */
	public static String firstCharToUpperCase(String str) {
		char firstChar = str.charAt(0);
		if (firstChar >= 'a' && firstChar <= 'z') {
			char[] arr = str.toCharArray();
			arr[0] -= ('a' - 'A');
			return new String(arr);
		}
		return str;
	}

	/**
	 * 字符串为 null 或者为 "" 时返回 true
	 */
	public static boolean isBlank(String str) {
		return str == null || "".equals(str.trim());
	}

	/**
	 * 字符串不为 null 而且不为 "" 时返回 true
	 */
	public static boolean hasText(String str) {
		return str != null && !"".equals(str.trim());
	}

	public static boolean hasText(String... strings) {
		if (strings == null)
			return false;
		for (String str : strings)
			if (str == null || "".equals(str.trim()))
				return false;
		return true;
	}

	public static boolean notNull(Object... paras) {
		if (paras == null)
			return false;
		for (Object obj : paras)
			if (obj == null)
				return false;
		return true;
	}

	/**
	 * 下划线转驼峰法
	 * 
	 * @param line
	 *            源字符串
	 * @param smallCamel
	 *            大小驼峰,是否为小驼峰
	 * @return 转换后的字符串
	 */
	public static String underline2Camel(String line, boolean smallCamel) {
		if (line == null || "".equals(line)) {
			return "";
		}
		StringBuffer sb = new StringBuffer();
		Pattern pattern = Pattern.compile("([A-Za-z\\d]+)(_)?");
		Matcher matcher = pattern.matcher(line);
		while (matcher.find()) {
			String word = matcher.group();
			sb.append(smallCamel && matcher.start() == 0 ? Character.toLowerCase(word.charAt(0)) : Character.toUpperCase(word.charAt(0)));
			int index = word.lastIndexOf('_');
			if (index > 0) {
				sb.append(word.substring(1, index).toLowerCase());
			} else {
				sb.append(word.substring(1).toLowerCase());
			}
		}
		return sb.toString();
	}

	/**
	 * 驼峰法转下划线
	 * 
	 * @param line
	 *            源字符串
	 * @return 转换后的字符串
	 */
	public static String camel2Underline(String line) {
		if (line == null || "".equals(line)) {
			return "";
		}
		line = String.valueOf(line.charAt(0)).toUpperCase().concat(line.substring(1));
		StringBuffer sb = new StringBuffer();
		Pattern pattern = Pattern.compile("[A-Z]([a-z\\d]+)?");
		Matcher matcher = pattern.matcher(line);
		while (matcher.find()) {
			String word = matcher.group();
			sb.append(word.toUpperCase());
			sb.append(matcher.end() == line.length() ? "" : "_");
		}
		return sb.toString();
	}

	public static String join(String[] stringArray) {
		StringBuilder sb = new StringBuilder();
		for (String s : stringArray)
			sb.append(s);
		return sb.toString();
	}

	public static String join(String[] stringArray, String separator) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < stringArray.length; i++) {
			if (i > 0)
				sb.append(separator);
			sb.append(stringArray[i]);
		}
		return sb.toString();
	}

	/**
	 * 长类名变短类名
	 * 
	 * @param longClassName
	 * @return
	 */
	public static String getShortClassName(String longClassName) {
		if (longClassName == null || "".equals(longClassName))
			return "";
		String[] strs = longClassName.trim().split("\\.");
		return strs[strs.length - 1];
	}

}
